//-----------------------------------------------------------------------
// <copyright file="Node.cpp" company="Microsoft">
//      Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// Module:
//      Node.cpp
//
// Description:
//
//-----------------------------------------------------------------------

#include "Common.h"

HRESULT CNodeApplication::AddContent(CONTENT_ID contentId, const unsigned char* pData, const DWORD cbData)
{
    HRESULT hr;
    CContent *pContent;
    
    pContent = GetContent(contentId);
    
    if (pContent)
    {
        hr = pContent->SetData(pData, cbData);
    }
    else
    {
        pContent = new(std::nothrow) CContent(contentId);
        
        if (pContent)
        {
            hr = pContent->SetData(pData, cbData);
            
            if (hr == S_OK)
            {
                try
                {
                    m_ContentMap.insert(CONTENTMAP::value_type(contentId, pContent));
                }
                catch(...)
                {
                    hr = E_FAIL;
                }
            }

            if (FAILED(hr))
            {
                delete pContent;
            }
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }

#if DBG
    WCHAR wszBuff[256];
    StringCchPrintf(wszBuff, COUNTOF(wszBuff), L"AddContent %s contentId=%d %c%c%c pContent=0x%X\r\n", GetTitle(), contentId, pData[0], pData[1], pData[2], pContent);
    OutputDebugString(wszBuff);
#endif

    if (pContent)
    {
        CNodeApplication *pAppNode = g_pDataManager->GetCurrentApplication();

        if (pAppNode)
        {
            if (IsEqualGUID(g_pDataManager->GetCurrentApplication()->m_guidApplicationId, this->m_guidApplicationId))
            {
                //
                // Special handling for the case that itself is the current application. (#9460)
                // The following code checks if any contents refer to the newly-added/updated content.
                // If there are any such contents, its views are invalidated.
                // This forces the view to calculate content layout before it renders contents next time.
                //
                for(CONTENTMAP::iterator it = m_ContentMap.begin(); it != m_ContentMap.end(); ++it)
                {
                    if (it->second != pContent)
                    {
                        if (it->second->HasImageReferenceOf(contentId))
                        {
                            it->second->InvalidateView();
                        }
                    }
                }
            }
        }
    }
    return hr;
}

HRESULT CNodeApplication::RemoveContent(CONTENT_ID contentId)
{
    CContent* pContent = GetContent(contentId);

    if (pContent)
    {
#if DBG
        WCHAR wszBuff[256];
        StringCchPrintf(wszBuff, COUNTOF(wszBuff), L"RemoveContent %s contentId=%d pContent=0x%X\r\n", GetTitle(), contentId, pContent);
        OutputDebugString(wszBuff);
#endif
        m_ContentMap.erase(contentId);  // is this raise exception?
    
        delete pContent;
    }
    
    return S_OK;
}

HRESULT CNodeApplication::RemoveAllContent()
{
#if DBG
    WCHAR wszBuff[256];
    StringCchPrintf(wszBuff, COUNTOF(wszBuff), L"RemoveAllContent %s\r\n", GetTitle());
    OutputDebugString(wszBuff);
#endif

    for(CONTENTMAP::iterator it = m_ContentMap.begin();
        it != m_ContentMap.end();
        ++it)
    {
#if DBG
        StringCchPrintf(wszBuff, COUNTOF(wszBuff), L"  ContentId=%d pContent=0x%X\r\n", it->first, it->second);
        OutputDebugString(wszBuff);
#endif
        
        // free memory
        delete it->second;
    }
    
    m_ContentMap.erase(m_ContentMap.begin(), m_ContentMap.end());
    
    if (g_pDataManager->GetCurrentApplication() == this)
    {
        // goto application menu
        g_pDataManager->SetCurrentContentId(CONTENT_ID_GLANCE);
        g_pDataManager->ClearContextMenu();
    }
    
    return S_OK;
}

CContent* CNodeApplication::GetContent(CONTENT_ID contentId)
{
    CContent* ret = NULL;
    CONTENTMAP::iterator it = m_ContentMap.find(contentId);
    
    if (it != m_ContentMap.end())
    {
        ret = it->second;
    }
    
    return ret;
}

VOID CNodeApplication::OnApplicationEnter()
{
    CContent *pContent = GetContent(CONTENT_ID_HOME);
    
    if (pContent)
    {
        pContent->OnContentEnter();
    }
}

//
// Call OnApplicationExit handler of all contents of this application.
// Content free parsed data and view objects.
//
VOID CNodeApplication::OnApplicationExit()
{
    for(CONTENTMAP::iterator it = m_ContentMap.begin();
        it != m_ContentMap.end();
        ++it)
    {
        it->second->OnApplicationExit();
    }
}

//
// Create fake content for Notification and initialize its view object.
// Although Windows SideShow notification is not SCF content, this function creates fake SCF content to be rendered by common rendering routines.
//
HRESULT CNodeNotification::InitializeView(HDC hdc, RECT& rect)
{
    HRESULT hr = S_OK;
    CScfTxtElement* pTxt;

    //
    // Notification Title
    //
    pTxt = new(std::nothrow) CScfTxtElement();
    if (pTxt)
    {
        pTxt->SetRgbAttr(CRenderer::GetDefaultTextColor());
        pTxt->AppendText(GetTitle(), (UINT)wcslen(GetTitle()));
        pTxt->AddEmRange(0, (int)wcslen(GetTitle()));               // Bold

        hr = m_fakeNotificationContent.AddChild(pTxt);      // pTxt will be freed pTxt in fake contetnt dtor.

        if (FAILED(hr))
        {
            delete pTxt;
        }
    }
    
    //
    // Notification Body
    //
    if (SUCCEEDED(hr))
    {
        pTxt = new(std::nothrow) CScfTxtElement();
        if (pTxt)
        {
            pTxt->SetRgbAttr(CRenderer::GetDefaultTextColor());
            pTxt->AppendText(GetBody(), (UINT)wcslen(GetBody()));
            
            hr = m_fakeNotificationContent.AddChild(pTxt);      // pTxt will be freed pTxt in fake contetnt dtor.
            
            if (FAILED(hr))
            {
                delete pTxt;
            }
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }
    
    if (SUCCEEDED(hr))
    {
        hr = m_view.Initialize(&m_fakeNotificationContent);
    }
    
    if (SUCCEEDED(hr))
    {
        hr = m_view.OnSize(hdc, rect.right - rect.left, rect.bottom - rect.top);
    }
    
    m_bViewInitialized = TRUE;
    
    return hr;
}

